
import json
import os
import importlib
from typing import List

from fastapi import FastAPI

from app.configs.config import fast_api_config
from app.configs.sys_config import (router_path,
                                    router_file_prefix,
                                    middleware_path,
                                    middleware_file_prefix)
from app.routers import BaseRouter
from app.utils.utils_path import file_path_to_model_path


class InitFastAPI:
    def __init__(self):
        self.fast_api = FastAPI(**fast_api_config)

        # app.add_middleware(my_middleware)
        self.auto_add_middleware()

        self.auto_include_router()
        self.write_openapi()

    def _get_all_module_path(self, path: str) -> List[str]:
        """
            获取所有模块
        """

        path_list: list = []
        for module_name in os.listdir(path):

            if module_name.startswith("__"):
                continue

            path_list.append(f"{router_path}/{module_name}")

        return path_list

    def _get_router_calss_by_model(self, module_path: str) -> List[BaseRouter]:

        router_class_list: List[BaseRouter] = []

        for full_file_name in os.listdir(module_path):
            if not full_file_name.endswith("py") \
                    or not full_file_name.startswith(router_file_prefix) \
                    or full_file_name.startswith("__"):
                # 如果不是 py 文件
                # 或者不是以 router 开头
                # 或者是 __ 开头
                #   则不处理
                continue

            # 文件夹名(模块名) 必须在 `app/routers` 下
            # 文件名和 类名必须一致(注：下划线后的字母必须大写)
            # 为了规范，尽量将 routers 写在前面
            # 例如：
            #   文件夹名（模块名）：routers_test
            #       文件名：routers_test.py 类名：RoutersTest
            #       文件名：routers_test_list.py 类名：RoutersTestList
            file_name = full_file_name.replace(".py", "")

            # 得到模块名
            full_module_name = file_path_to_model_path(
                f"{module_path}/{file_name}")

            # 得到类名
            class_name = file_name.title().replace("_", "")

            # 导入模块
            module = importlib.import_module(full_module_name)

            # 得到路由类
            router_class = getattr(module, class_name)

            if router_class:
                router_class_list.append(router_class)

        return router_class_list

    def auto_add_middleware(self) -> None:
        """
            动态添加 middleware 
        """
        all_router_class_list = []
        middleware_path_list = self._get_all_module_path(middleware_path)
        # TODO

    def auto_include_router(self) -> None:
        """
            动态添加 router 
        """
        # 得到所有 model path
        all_router_class_list = []
        module_path_list = self._get_all_module_path(router_path)

        # 得到所有路由类
        for module_path in module_path_list:
            router_class_list = self._get_router_calss_by_model(module_path)
            all_router_class_list.extend(router_class_list)

        for router_class in router_class_list:
            # 实例化类对象
            router_instance: BaseRouter = router_class()

            # 添加路由
            self.fast_api.include_router(router_instance.router)

    def write_openapi(self):
        """
            因为动态添加 router 的原因
            所以需要手动更新 openapi.json
        """
        # 手动生成文档
        openapi_schema = self.fast_api.openapi()

        # 将文档保存到文件
        with open("openapi.json", "w") as f:
            json.dump(openapi_schema, f, indent=4)


init_fastapi = InitFastAPI()

fast_api = init_fastapi.fast_api
